1 Preparations for analysis

Loading packages to simulate and manipulate data.

library(MASS)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ───────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.1.1     ✓ dplyr   1.0.6
✓ tidyr   1.1.3     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
── Conflicts ──────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
x dplyr::select() masks MASS::select()

2 Simulate data

Data generation was performed according to the following conditions:

  • Correlations: 0.12, 0.20, 0.31, 0.50
  • Sample sizes: 50, 100, 250, 500, 1000
  • Number of replications: 1000

In this way, 20 dataframes are generated with different amounts of data within each of them, which will have 1,000 replications. In total, 20,000 dataframes with observations for analysis.

2.1 Generate matrices and observations

Create the variables that indicate the conditions

set.seed(2020) 
r <- c(0.12, 0.20, 0.31, 0.50) ## Correlaciones 
n <- c(50, 100, 250, 500, 1000) ## Tamaño de muestra
replic <- 1000
# Generar las matrices de correlación
sigma <- list()
for (i in seq_along(r)) { 
  sigma[[i]] <- matrix(data = c(1, rep(r[i], 2), 1),
                       nrow = 2,
                       ncol = 2)
}


# Generar los datos de correlación
df_cor <- list()
for (i in seq_along(sigma)) {
  df_cor[[i]] <- list()
  for (j in seq_along(n)) {
    df_cor[[i]][[j]] <- list()
    for (k in 1:replic) {
      df_cor[[i]][[j]][[k]] <- mvrnorm(n     = n[j],
                                       mu    = rep(0, 2),
                                       Sigma = sigma[[i]]) %>% 
        as_tibble()
    }
  }
}
The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
Using compatibility `.name_repair`.

2.2 Format the data as dataframe / tibbles

We will assemble the list object in such a way that we can identify by columns the correlation, sample size and replicate number of each observation.

2.3 Add outliers

Five percent of the data in each data frame will be randomly replaced by outlier correlations different from the one generated. For example, in the case of a dataframe with a correlation of 0.12 and a sample size of 50, 3 pairs of correlations will be randomly replaced with 3 pairs of correlations generated with correlations of 0.20, 0.31 and 0.50.

# Add the number of outliers to be added and their locations Outliers at 5%.
df_work <- df_nest %>% 
  rowwise() %>% 
  mutate(
    ratio_outlier = map_dbl(n,
                        ~ ceiling(0.05*n)),
    posici_rep_m3 = map2(n, ratio_outlier,
                         ~ sample(1:.x, .y)),
    posici_rep_m6 = map2(n, ratio_outlier,
                         ~ sample(1:.x, .y)),
    posici_rep_m3v1 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m3v2 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m3v3 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m6v1 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y)),
    posici_rep_m6v2 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y)),
    posici_rep_m6v3 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y))
  )

# Add correlations that were not considered
df_work <- df_work %>% 
  mutate(
    correla_a = r[which(correlacion != r)[1]],
    correla_b = r[which(correlacion != r)[2]],
    correla_c = r[which(correlacion != r)[3]]
  )

On the correlations identified to be generated, the data matrix necessary for the multivariate simulation is created as an outlier.

df_work <- df_work %>% 
  mutate(
    matrix = map(correlacion,
                 ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                          nrow = 2,
                          ncol = 2)),
    matrix_a = map(correla_a,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2)),
    matrix_b = map(correla_b,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2)),
    matrix_c = map(correla_c,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2))
  ) %>% 
  ungroup()

Aggregate outliers are of 2 types: they vary only by the mean and they vary by the mean and its matrix:

  • outlier_m3: Varies by an mean of 3
  • outlier_m6: Varies by an mean of 6
  • outlier_m3v1: Varies by an mean of 3 and matrix a
  • outlier_m3v2: Varies by an mean of 3 and matrix b
  • outlier_m3v3: Varies by an mean of 3 and matrix c
  • outlier_m6v1: Varies by an mean of 6 and matrix a
  • outlier_m6v2: Varies by an mean of 6 and matrix b
  • outlier_m6v3: Varies by an mean of 6 and matrix c
set.seed(2019) 

df_work <- df_work %>% 
  mutate(
    outlier_m3 = map2(ratio_outlier, matrix, 
                      ~ mvrnorm(n     = .x,
                                mu    = rep(3, 2),
                                Sigma = .y) %>% 
                        as_tibble()),
    outlier_m6 = map2(ratio_outlier, matrix,
                      ~ mvrnorm(n     = .x,
                                mu    = rep(6, 2),
                                Sigma = .y) %>% 
                        as_tibble()),
    outlier_m3v1 = map2(ratio_outlier, matrix_a, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m3v2 = map2(ratio_outlier, matrix_b, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m3v3 = map2(ratio_outlier, matrix_c, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v1 = map2(ratio_outlier, matrix_a, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v2 = map2(ratio_outlier, matrix_b, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v3 = map2(ratio_outlier, matrix_c, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble())
  )

These new simulated outlier correlations will be inserted into the initially calculated random positions in each dataframe.

df_work <- df_work %>% 
  mutate(
    data_out_m3 = pmap(list(data, posici_rep_m3, outlier_m3),
                       ~ ..1 %>% 
                         slice(- ..2) %>% 
                         bind_rows(..3)),
    data_out_m6 = pmap(list(data, posici_rep_m6, outlier_m6),
                       ~ ..1 %>% 
                         slice(- ..2) %>% 
                         bind_rows(..3)),
    data_out_m3v1 = pmap(list(data, posici_rep_m3v1, outlier_m3v1),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m3v2 = pmap(list(data, posici_rep_m3v2, outlier_m3v2),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m3v3 = pmap(list(data, posici_rep_m3v3, outlier_m3v3),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v1 = pmap(list(data, posici_rep_m6v1, outlier_m6v1),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v2 = pmap(list(data, posici_rep_m6v2, outlier_m6v2),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v3 = pmap(list(data, posici_rep_m6v3, outlier_m6v3),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3))
  )

Additionally, new dataframes with the same correlation conditions, sample size and number of replications with non-normal data distributions are generated using the algorithm of Vale and Maurelli (1983).

Non-normality conditions were generated on the basis of the work of Sheng & Sheng (2012):

  • skewness = 0.00, kurtosis = − 1.385 (symmetric platykurtic distribution);
  • skewness = 0.00, kurtosis = 25 (symmetric leptokurtic distribution);
  • skewness = 0.96, kurtosis = 0.13 (non-symmetric distribution);
  • skewness = 0.48, kurtosis = − 0.92 (non-symmetric platykurtic distribution);
  • skewness = 2.50, kurtosis = 25 (non-symmetric leptokurtic distribution).
set.seed(2021) 
library(semTools)

df_work <- df_work %>% 
  mutate(
    data_nonorm1 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = c(0),
                                     kurtosis = c(-1.385)) %>% # symmetric platykurtic distribution
                          as_tibble()),
    data_nonorm2 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0,
                                     kurtosis = 25) %>% # symmetric leptokurtic distribution 
                          as_tibble()),
    data_nonorm3 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0.96,
                                     kurtosis = 0.13) %>% # non-symmetric distribution
                          as_tibble()),
    data_nonorm4 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0.48,
                                     kurtosis = -0.92) %>% # non-symmetric platykurtic distribution
                          as_tibble()),
    data_nonorm5 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 2.5,
                                     kurtosis = 25) %>% # non-symmetric leptokurtic distribution
                          as_tibble())
  )

Finally, the variables that will no longer be used are eliminated.

df_work <- df_work %>% 
  select(-c(ratio_outlier:outlier_m6v3))

df_work

3 Calculation of correlations

3.1 Format tidy data

df_work_tidy <- df_work %>% 
  pivot_longer(
    cols = data:data_nonorm5,
    names_to = "Tipo_Sim",
    values_to = "Data"
  )

3.2 Settings multicore

library(multidplyr)

if (Sys.getenv("RSTUDIO") == "1" && !nzchar(Sys.getenv("RSTUDIO_TERM")) && 
    (Sys.info()["sysname"] == "Darwin" || Sys.info()["sysname"] == "Linux") && 
    getRversion() >= "4.0.0") {
  parallel:::setDefaultClusterOptions(setup_strategy = "sequential")
}

cluster <- new_cluster(parallel::detectCores())

3.3 Correlations

df_work_tidy <- df_work_tidy %>% 
  partition(cluster) %>% 
  mutate(
    cort_pears = purrr::map(Data,
                            ~ cor.test(.x$V1, .x$V2,
                                       method = "pearson")),
    cort_spear = purrr::map(Data,
                            ~ cor.test(.x$V1, .x$V2,
                                       method = "spearman")),
    cort_winso = purrr::map(Data,
                            ~ WRS2::wincor(.x$V1, .x$V2,
                                           tr = 0.2))
  ) %>% 
  collect()

3.4 Obtain the coefficients

df_work_tidy <- df_work_tidy %>% 
  mutate(
    coef_pears = map_dbl(cort_pears,
                         ~ .x$estimate),
    coef_spear = map_dbl(cort_spear,
                         ~ .x$estimate),
    coef_winso = map_dbl(cort_winso,
                         ~ .x$cor),
    pvalue_pears = map_dbl(cort_pears,
                           ~ .x$p.value),
    pvalue_spear = map_dbl(cort_spear,
                           ~ .x$p.value),
    pvalue_winso = map_dbl(cort_winso,
                           ~ .x$p.value)
  )

df_work_tidy_simp <- df_work_tidy %>% 
  select(-c(Data:cort_winso))

df_work_tidy_simp

3.5 Generate plot about p-value

3.6 Plot with complete conditions

3.6.1 Data format

df_work_tidy_pvalue <- df_work_tidy_simp %>% 
  mutate(
    across(c(pvalue_pears:pvalue_winso),
           ~ case_when(
             .x < .05 ~ 1,
             TRUE ~ 0
           )),
    correlacion = factor(correlacion, 
                         labels = c("0.12", "0.20",
                                    "0.31", "0.50")) 
  ) %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  summarise(
    across(
      c(pvalue_pears:pvalue_winso),
      ~ mean(.)
    )
  ) %>% 
  ungroup() %>% 
  pivot_longer(
    cols = pvalue_pears:pvalue_winso,
    names_to = "Estimator",
    values_to = "Power"
  ) %>% 
  mutate(
    Estimator = fct_recode(Estimator,
                           "Pearson" = "pvalue_pears",
                           "Spearman" = "pvalue_spear",
                           "Winsorized" = "pvalue_winso")
  )


df_work_tidy_pvalue_A <- df_work_tidy_pvalue %>% 
  mutate(
    Tipo_Sim = fct_recode(Tipo_Sim,
                          "MVN" = "data",
                          "OL M3" = "data_out_m3",
                          "OL M6" = "data_out_m6",
                          "OL M3 V1" = "data_out_m3v1",
                          "OL M3 V2" = "data_out_m3v2",
                          "OL M3 V3" = "data_out_m3v3",
                          "OL M6 V1" = "data_out_m6v1",
                          "OL M6 V2" = "data_out_m6v2",
                          "OL M6 V3" = "data_out_m6v3",
                          "No-MVN A" = "data_nonorm1",
                          "No-MVN B" = "data_nonorm2",
                          "No-MVN C" = "data_nonorm3",
                          "No-MVN D" = "data_nonorm4",
                          "No-MVN E" = "data_nonorm5"),
    Tipo_Sim = fct_relevel(Tipo_Sim,
                           "MVN", "OL M3", "OL M6", "OL M3 V1", 
                           "OL M3 V2", "OL M3 V3", "OL M6 V1",
                           "OL M6 V2", "OL M6 V3")
  ) %>% 
  arrange(correlacion, n, Tipo_Sim)

3.6.2 Plot generation

plot_power_correlation_A <- ggplot(df_work_tidy_pvalue_A,
       aes(x = Tipo_Sim,
           y = Power,
           shape = Estimator,
           linetype = Estimator,
           group = Estimator)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(0, 1),
                     breaks = seq(0, 1, 0.2)) +
    labs(title = "",
         x = "Simulation conditions",
         y = "Power Statistics") +
  facet_grid(correlacion ~ n) +
  theme_bw() + 
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 55, 
                               vjust= 1,
                               hjust = 1),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

3.7 Plot with summarised conditions

3.7.1 Data format

df_work_tidy_pvalue_B <- df_work_tidy_pvalue %>%
  mutate(
    Tipo_Sim = fct_collapse(Tipo_Sim,
                            "MVN" = "MVN",
                            "MVN OL M3" = "OL M3",
                            "MVN OL M6" = "OL M6",
                            "MVN OL M3V" = c("OL M3 V1", "OL M3 V2", "OL M3 V3"),
                            "MVN OL M6V" = c("OL M6 V1", "OL M6 V2", "OL M6 V3"),
                            "No-MVN" = c("No-MVN A", "No-MVN C", "No-MVN D"),
                            "No-MVN ks+" = c("No-MVN B", "No-MVN E")
    )
  ) 

df_work_tidy_pvalue_B <- df_work_tidy_pvalue_B %>% 
  group_by(correlacion, n, Tipo_Sim, Estimator) %>% 
  summarise(
    across(everything(), mean)
  ) %>% 
  ungroup()

df_work_tidy_pvalue_B

3.7.2 Plot generation

plot_power_correlation_B <- ggplot(df_work_tidy_pvalue_B,
       aes(x = Tipo_Sim,
           y = Power,
           shape = Estimator,
           linetype = Estimator,
           group = Estimator)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(0, 1),
                     breaks = seq(0, 1, 0.2)) +
    labs(title = "",
         x = "Simulation conditions",
         y = "Power Statistics") +
  facet_grid(correlacion ~ n) +
  theme_bw() + 
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 45, 
                               vjust= 1,
                               hjust = 1),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

4 Evaluate simulation

4.1 Calculate RMSEA and Bias

df_work_tidy_simp <- df_work_tidy_simp %>% 
  rowwise() %>% 
  mutate(
    dif_pears = (coef_pears - correlacion)/correlacion,
    dif_spear = (coef_spear - correlacion)/correlacion,
    dif_winso = (coef_winso - correlacion)/correlacion
  ) %>% 
  ungroup()

df_work_tidy_simp <- df_work_tidy_simp %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  summarise(
    rmsea_pears = sqrt(sum(dif_pears^2)/1000),
    sesgo_pears = (sum(dif_pears)/1000),
    rmsea_spear = sqrt(sum(dif_spear^2)/1000),
    sesgo_spear = (sum(dif_spear)/1000),
    rmsea_winso = sqrt(sum(dif_winso^2)/1000),
    sesgo_winso = (sum(dif_winso)/1000)
  ) %>% 
  ungroup()
`summarise()` has grouped output by 'correlacion', 'n'. You can override using the `.groups` argument.
df_work_tidy_simp

4.2 Recode simulation types

df_work_tidy_simp <- df_work_tidy_simp %>% 
  mutate(
    Tipo_Sim = fct_recode(Tipo_Sim,
                          "MVN" = "data",
                          "OL M3" = "data_out_m3",
                          "OL M6" = "data_out_m6",
                          "OL M3 V1" = "data_out_m3v1",
                          "OL M3 V2" = "data_out_m3v2",
                          "OL M3 V3" = "data_out_m3v3",
                          "OL M6 V1" = "data_out_m6v1",
                          "OL M6 V2" = "data_out_m6v2",
                          "OL M6 V3" = "data_out_m6v3",
                          "No-MVN A" = "data_nonorm1",
                          "No-MVN B" = "data_nonorm2",
                          "No-MVN C" = "data_nonorm3",
                          "No-MVN D" = "data_nonorm4",
                          "No-MVN E" = "data_nonorm5"),
    Tipo_Sim = fct_relevel(Tipo_Sim,
                           "MVN", "OL M3", "OL M6", "OL M3 V1", 
                           "OL M3 V2", "OL M3 V3", "OL M6 V1",
                           "OL M6 V2", "OL M6 V3")
  ) %>% 
  arrange(correlacion, n, Tipo_Sim)

4.3 Complete table about RMSEA and Bias

df_work_tidy_simp_A <- df_work_tidy_simp %>% 
  relocate(contains("sesgo"), .after = "rmsea_winso")

df_work_tidy_simp_A

4.4 Recalculation of RMSEA and Bias grouping conditions

df_work_tidy_simp_B <- df_work_tidy_simp %>%
  mutate(
    Tipo_Sim = fct_collapse(Tipo_Sim,
                            "MVN" = "MVN",
                            "MVN OL M3" = "OL M3",
                            "MVN OL M6" = "OL M6",
                            "MVN OL M3V" = c("OL M3 V1", "OL M3 V2", "OL M3 V3"),
                            "MVN OL M6V" = c("OL M6 V1", "OL M6 V2", "OL M6 V3"),
                            "No-MVN" = c("No-MVN A", "No-MVN C", "No-MVN D"),
                            "No-MVN ks+" = c("No-MVN B", "No-MVN E")
    )
  ) %>% 
  relocate(contains("sesgo"), .after = "rmsea_winso")

df_work_tidy_simp_B <- df_work_tidy_simp_B %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  summarise(
    across(everything(), mean)
  ) %>% 
  ungroup()
`summarise()` has grouped output by 'correlacion', 'n'. You can override using the `.groups` argument.
df_work_tidy_simp_B

4.5 Format tidy data

df_work_tidy_simp <- df_work_tidy_simp %>% 
  pivot_longer(
    cols = rmsea_pears:sesgo_winso,
    names_to = "Ajuste",
    values_to = "Valor"
  ) %>% 
  mutate(
    Ajuste = fct_recode(Ajuste,
                        "RMSE Pearson" = "rmsea_pears",
                        "RMSE Spearman" = "rmsea_spear",
                        "RMSE Winsorized" = "rmsea_winso",
                        "Sesgo Pearson" = "sesgo_pears",
                        "Sesgo Spearman" = "sesgo_spear",
                        "Sesgo Winsorized" = "sesgo_winso")
  )

df_work_tidy_simp

4.6 Plots

plot_assess_A <- df_work_tidy_simp %>%
  mutate(
    correlacion = factor(correlacion, 
                         labels = c("0.12", "0.20",
                                    "0.31", "0.50"))
  ) %>% 
  filter(correlacion != "0.50") %>% 
  ggplot(aes(x = Tipo_Sim, y = Valor,
             # colour = Ajuste,
             shape = Ajuste,
             linetype = Ajuste,
             group = Ajuste)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(-0.5, 5.5),
                     breaks = seq(-0.5, 5.5, 1)) +
  labs(title = "",
       x = "Condiciones de Simulación",
       y = "") +
  # scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  facet_grid(correlacion ~ n) +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 90),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

plot_assess_B <- df_work_tidy_simp %>%
  mutate(
    correlacion = factor(correlacion, 
                         labels = c("0.12", "0.20",
                                    "0.31", "0.50"))
  ) %>% 
  filter(correlacion != "0.50") %>% 
  ggplot(aes(x = Tipo_Sim, y = Valor,
             # colour = Ajuste,
             shape = Ajuste,
             linetype = Ajuste,
             group = Ajuste)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(-0.5, 5.5),
                     breaks = seq(-0.5, 5.5, 1)) +
  labs(title = "",
       x = "Condiciones de Simulación",
       y = "") +
  # scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  facet_grid(n ~ correlacion) +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 90),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

5 Evaluate normality

5.1 Calculation of kurtosis and skewness for each variable

library(e1071)

df_work_tidy_evaluate <- df_work_tidy %>% 
  mutate(
    kurtosis_v1 = map_dbl(Data,
                          ~ kurtosis(.x$V1, type = 2)),
    kurtosis_v2 = map_dbl(Data,
                          ~ kurtosis(.x$V2, type = 2)),
    skewness_v1 = map_dbl(Data,
                          ~ skewness(.x$V1, type = 2)),
    skewness_v2 = map_dbl(Data,
                          ~ skewness(.x$V2, type = 2))
  ) %>% 
  select(-c(cort_pears:coef_winso))

df_work_tidy_evaluate

5.2 Calculation evaluating multivariate normality

5.2.1 Evaluation

df_work_tidy_evaluate <- df_work_tidy_evaluate %>% 
  partition(cluster) %>% 
  mutate(
    Normal_multi_r = purrr::map_chr(Data,
                             ~ MVN::mvn(.x)$multivariateNormality$Result[3]),
    Normal_multi_r = ifelse(Normal_multi_r == "YES", "Si", "No")
  ) %>% 
  collect()

5.2.2 Categorize by kurtosis and skewness

df_work_tidy_evaluate <- df_work_tidy_evaluate %>% 
  mutate(
    norm_uni = ifelse(kurtosis_v1 >= - 1.5 & kurtosis_v1 <= 1.5 &
                        skewness_v1 >= - 1.5 & skewness_v1 <= 1.5 &
                        kurtosis_v2 >= - 1.5 & kurtosis_v2 <= 1.5 &
                        skewness_v2 >= - 1.5 & skewness_v2 <= 1.5, 
                      "Si", "No")
  )

5.3 Format tidy data

df_work_tidy_evaluate <- df_work_tidy_evaluate %>%
  mutate(
    Tipo_Sim = fct_recode(Tipo_Sim,
                          "MVN" = "data",
                          "OL M3" = "data_out_m3",
                          "OL M6" = "data_out_m6",
                          "OL M3 V1" = "data_out_m3v1",
                          "OL M3 V2" = "data_out_m3v2",
                          "OL M3 V3" = "data_out_m3v3",
                          "OL M6 V1" = "data_out_m6v1",
                          "OL M6 V2" = "data_out_m6v2",
                          "OL M6 V3" = "data_out_m6v3",
                          "No-MVN A" = "data_nonorm1",
                          "No-MVN B" = "data_nonorm2",
                          "No-MVN C" = "data_nonorm3",
                          "No-MVN D" = "data_nonorm4",
                          "No-MVN E" = "data_nonorm5"),
    Tipo_Sim = fct_relevel(Tipo_Sim,
                           "MVN", "OL M3", "OL M6", "OL M3 V1", 
                           "OL M3 V2", "OL M3 V3", "OL M6 V1",
                           "OL M6 V2", "OL M6 V3")
  ) %>% 
  arrange(correlacion, n, Tipo_Sim)

df_work_tidy_evaluate

5.4 Data format for evaluation

Complete:

df_work_tidy_A <- df_work_tidy_evaluate %>% 
  select(correlacion:Tipo_Sim, Normal_multi_r:norm_uni) %>%
  pivot_longer(
    cols = Normal_multi_r:norm_uni,
    names_to = "Evaluación Normalidad",
    values_to = "Dx"
  ) %>%
  mutate(
    `Evaluación Normalidad` = ifelse(`Evaluación Normalidad` == "Normal_multi_r",
                                     "Normalidad mardia", "Normalidad As y Ks")
  )

Grouped:

df_work_tidy_simp_B <- df_work_tidy_evaluate %>%
  mutate(
    Tipo_Sim = fct_collapse(Tipo_Sim,
                            "MVN" = "MVN",
                            "MVN OL M3" = "OL M3",
                            "MVN OL M6" = "OL M6",
                            "MVN OL M3V" = c("OL M3 V1", "OL M3 V2", "OL M3 V3"),
                            "MVN OL M6V" = c("OL M6 V1", "OL M6 V2", "OL M6 V3"),
                            "No-MVN" = c("No-MVN A", "No-MVN C", "No-MVN D"),
                            "No-MVN ks+" = c("No-MVN B", "No-MVN E")
    )
  ) %>%
  select(correlacion:Tipo_Sim, Normal_multi_r:norm_uni) %>%
  pivot_longer(
    cols = Normal_multi_r:norm_uni,
    names_to = "Evaluación Normalidad",
    values_to = "Dx"
  ) %>%
  mutate(
    `Evaluación Normalidad` = ifelse(`Evaluación Normalidad` == "Normal_multi_r",
                                     "Normalidad mardia", "Normalidad As y Ks")
  )

5.5 Plots

5.5.1 Plot Mardia full

Calculate the percentage of dataframes identified as multivariate normal in each condition.

df_work_tidy_A_mardia <- df_work_tidy_A %>% 
  filter(`Evaluación Normalidad` == "Normalidad mardia") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

df_work_tidy_A_mardia

Plot generation:

plot_A_mardia <- df_work_tidy_A_mardia %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 

5.5.2 Plot Skewness and Kurtosis full

Calculate the percentage of dataframes identified as univariate normality in each condition.

df_work_tidy_A_as_ks <- df_work_tidy_A %>% 
  filter(`Evaluación Normalidad` == "Normalidad As y Ks") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

Plot generation:

plot_A_as_ks <- df_work_tidy_A_as_ks %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 

5.5.3 Plot Mardia grouped

Calculate the percentage of dataframes identified as multivariate normal in each condition.

df_work_tidy_B_mardia <- df_work_tidy_simp_B %>% 
  filter(`Evaluación Normalidad` == "Normalidad mardia") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

Plot generation:

plot_B_mardia <- df_work_tidy_B_mardia %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 

5.5.4 Plot Skewness and Kurtosis grouped

Calculate the percentage of dataframes identified as univariate normality in each condition.

df_work_tidy_B_as_ks <- df_work_tidy_simp_B %>% 
  filter(`Evaluación Normalidad` == "Normalidad As y Ks") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

Plot Generation:

plot_B_as_ks <- df_work_tidy_B_as_ks %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 

LS0tCnRpdGxlOiAiU2ltdWxhdGlvbiBvZiBjb3JyZWxhdGlvbiBlc3RpbWF0b3JzIGZvciBub3JtYWwgYW5kIG5vbi1ub3JtYWwgY29ycmVsYXRpb25zIgpkYXRlOiAiMDMvMDQvMjAyMSIKYXV0aG9yOgogIC0gbmFtZTogSm9zw6kgVmVudHVyYS1MZcOzbgogICAgZW1haWw6IGpvc2UudmVudHVyYUB1cG4ucGUKICAgIGFmZmlsaWF0aW9uOiBVbml2ZXJzaWRhZCBQcml2YWRhIGRlbCBOb3J0ZQogIC0gbmFtZTogQnJpYW4gTi4gUGXDsWEtQ2FsZXJvCiAgICBlbWFpbDogYnJpYW5tc21AZ21haWwuY29tCiAgICBhZmZpbGlhdGlvbjogR3J1cG8gZGUgRXN0dWRpb3MgQXZhbmNlcyBlbiBNZWRpY2nDs24gUHNpY29sw7NnaWNhLCBVbml2ZXJzaWRhZCBOYWNpb25hbCBNYXlvciBkZSBTYW4gTWFyY29zLCBMaW1hLCBQZXLDugpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgaGlnaGxpZ2h0OiBrYXRlCiAgICB0aGVtZTogZmxhdGx5Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIFByZXBhcmF0aW9ucyBmb3IgYW5hbHlzaXMKCkxvYWRpbmcgcGFja2FnZXMgdG8gc2ltdWxhdGUgYW5kIG1hbmlwdWxhdGUgZGF0YS4gCgpgYGB7cn0KbGlicmFyeShNQVNTKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKIyBTaW11bGF0ZSBkYXRhCgpEYXRhIGdlbmVyYXRpb24gd2FzIHBlcmZvcm1lZCBhY2NvcmRpbmcgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKLSBDb3JyZWxhdGlvbnM6IDAuMTIsIDAuMjAsIDAuMzEsIDAuNTAKLSBTYW1wbGUgc2l6ZXM6IDUwLCAxMDAsIDI1MCwgNTAwLCAxMDAwCi0gTnVtYmVyIG9mIHJlcGxpY2F0aW9uczogMTAwMAoKSW4gdGhpcyB3YXksIDIwICpkYXRhZnJhbWVzKiBhcmUgZ2VuZXJhdGVkIHdpdGggZGlmZmVyZW50IGFtb3VudHMgb2YgZGF0YSB3aXRoaW4gZWFjaCBvZiB0aGVtLCB3aGljaCB3aWxsIGhhdmUgMSwwMDAgKnJlcGxpY2F0aW9ucyouIEluIHRvdGFsLCAyMCwwMDAgKmRhdGFmcmFtZXMqIHdpdGggb2JzZXJ2YXRpb25zIGZvciBhbmFseXNpcy4KCgojIyBHZW5lcmF0ZSBtYXRyaWNlcyBhbmQgb2JzZXJ2YXRpb25zCgpDcmVhdGUgdGhlIHZhcmlhYmxlcyB0aGF0IGluZGljYXRlIHRoZSBjb25kaXRpb25zCgpgYGB7cn0Kc2V0LnNlZWQoMjAyMCkgCnIgPC0gYygwLjEyLCAwLjIwLCAwLjMxLCAwLjUwKSAjIyBDb3JyZWxhdGlvbnMgCm4gPC0gYyg1MCwgMTAwLCAyNTAsIDUwMCwgMTAwMCkgIyMgU2FtcGxlIHNpemVzCnJlcGxpYyA8LSAxMDAwCmBgYAoKCmBgYHtyfQpzaWdtYSA8LSBsaXN0KCkKZm9yIChpIGluIHNlcV9hbG9uZyhyKSkgeyAKICBzaWdtYVtbaV1dIDwtIG1hdHJpeChkYXRhID0gYygxLCByZXAocltpXSwgMiksIDEpLAogICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLAogICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQp9CgoKIyBHZW5lcmFyIGxvcyBkYXRvcyBkZSBjb3JyZWxhY2nDs24KZGZfY29yIDwtIGxpc3QoKQpmb3IgKGkgaW4gc2VxX2Fsb25nKHNpZ21hKSkgewogIGRmX2NvcltbaV1dIDwtIGxpc3QoKQogIGZvciAoaiBpbiBzZXFfYWxvbmcobikpIHsKICAgIGRmX2NvcltbaV1dW1tqXV0gPC0gbGlzdCgpCiAgICBmb3IgKGsgaW4gMTpyZXBsaWMpIHsKICAgICAgZGZfY29yW1tpXV1bW2pdXVtba11dIDwtIG12cm5vcm0obiAgICAgPSBuW2pdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgwLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSBzaWdtYVtbaV1dKSAlPiUgCiAgICAgICAgYXNfdGliYmxlKCkKICAgIH0KICB9Cn0KYGBgCgojIyBGb3JtYXQgdGhlIGRhdGEgYXMgZGF0YWZyYW1lIC8gdGliYmxlcwoKV2Ugd2lsbCBhc3NlbWJsZSB0aGUgbGlzdCBvYmplY3QgaW4gc3VjaCBhIHdheSB0aGF0IHdlIGNhbiBpZGVudGlmeSBieSBjb2x1bW5zIHRoZSBjb3JyZWxhdGlvbiwgc2FtcGxlIHNpemUgYW5kIHJlcGxpY2F0ZSBudW1iZXIgb2YgZWFjaCBvYnNlcnZhdGlvbi4KCmBgYHtyfQojIFVuaXIgbG9zIGRhdG9zIHkgcGFzYXJsbyBhIGZvcm1hdG8gdGlkeQp0ZW1wIDwtIGRmX2NvcgpkZl9jb3IgPC0gbGlzdCgpCmZvciAoaSBpbiBzZXFfYWxvbmcoc2lnbWEpKSB7CiAgZGZfY29yW1tpXV0gPC0gbGlzdCgpCiAgZm9yIChqIGluIHNlcV9hbG9uZyhuKSkgewogICAgZGZfY29yW1tpXV1bW2pdXSA8LSB0ZW1wW1tpXV1bW2pdXSAlPiUgCiAgICAgIGJpbmRfcm93cyguaWQgPSAicmVwbGljIikgJT4lIAogICAgICBtdXRhdGUocmVwbGljID0gYXMubnVtZXJpYyhyZXBsaWMpKQogIH0KICBkZl9jb3JbW2ldXSA8LSBkZl9jb3JbW2ldXSAlPiUgCiAgICBiaW5kX3Jvd3MoLmlkID0gIm4iKSAlPiUgCiAgICBtdXRhdGUobiA9IHJlY29kZShuLCAiMSIgPSA1MCwgIjIiID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgIjMiID0gMjUwLCAiNCIgPSA1MDAsIAogICAgICAgICAgICAgICAgICAgICAgIjUiID0gMTAwMCkpCn0KCmRmX2NvciA8LSBkZl9jb3IgJT4lIAogIGJpbmRfcm93cyguaWQgPSAiY29ycmVsYWNpb24iKSAlPiUgCiAgbXV0YXRlKGNvcnJlbGFjaW9uID0gcmVjb2RlKGNvcnJlbGFjaW9uLCAiMSIgPSAwLjEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMiIgPSAwLjIwLCAiMyIgPSAwLjMxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNCIgPSAwLjUwKSkgJT4lIAogIGFycmFuZ2UoY29ycmVsYWNpb24sIG4sIHJlcGxpYykKCiMgQ3JlYXIgZGF0YSBuZXN0CmRmX25lc3QgPC0gZGZfY29yICU+JSAKICBuZXN0KGRhdGEgPSBjKFYxLCBWMikpCgpybSh0ZW1wLCBpLCBqLCBrKQpgYGAKCiMjIEFkZCBvdXRsaWVycyAKCkZpdmUgcGVyY2VudCBvZiB0aGUgZGF0YSBpbiBlYWNoIGRhdGEgZnJhbWUgd2lsbCBiZSByYW5kb21seSByZXBsYWNlZCBieSBvdXRsaWVyIGNvcnJlbGF0aW9ucyBkaWZmZXJlbnQgZnJvbSB0aGUgb25lIGdlbmVyYXRlZC4gRm9yIGV4YW1wbGUsIGluIHRoZSBjYXNlIG9mIGEgZGF0YWZyYW1lIHdpdGggYSBjb3JyZWxhdGlvbiBvZiAwLjEyIGFuZCBhIHNhbXBsZSBzaXplIG9mIDUwLCAzIHBhaXJzIG9mIGNvcnJlbGF0aW9ucyB3aWxsIGJlIHJhbmRvbWx5IHJlcGxhY2VkIHdpdGggMyBwYWlycyBvZiBjb3JyZWxhdGlvbnMgZ2VuZXJhdGVkIHdpdGggY29ycmVsYXRpb25zIG9mIDAuMjAsIDAuMzEgYW5kIDAuNTAuCgpgYGB7cn0KIyBBZGQgdGhlIG51bWJlciBvZiBvdXRsaWVycyB0byBiZSBhZGRlZCBhbmQgdGhlaXIgbG9jYXRpb25zIE91dGxpZXJzIGF0IDUlLgpkZl93b3JrIDwtIGRmX25lc3QgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgbXV0YXRlKAogICAgcmF0aW9fb3V0bGllciA9IG1hcF9kYmwobiwKICAgICAgICAgICAgICAgICAgICAgICAgfiBjZWlsaW5nKDAuMDUqbikpLAogICAgcG9zaWNpX3JlcF9tMyA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2FtcGxlKDE6LngsIC55KSksCiAgICBwb3NpY2lfcmVwX202ID0gbWFwMihuLCByYXRpb19vdXRsaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTN2MSA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICB+IHNhbXBsZSgxOi54LCAueSkpLAogICAgcG9zaWNpX3JlcF9tM3YyID0gbWFwMihuLCByYXRpb19vdXRsaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2FtcGxlKDE6LngsIC55KSksCiAgICBwb3NpY2lfcmVwX20zdjMgPSBtYXAyKG4sIHJhdGlvX291dGxpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTZ2MSA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTZ2MiA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTZ2MyA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKQogICkKCiMgQWRkIGNvcnJlbGF0aW9ucyB0aGF0IHdlcmUgbm90IGNvbnNpZGVyZWQKZGZfd29yayA8LSBkZl93b3JrICU+JSAKICBtdXRhdGUoCiAgICBjb3JyZWxhX2EgPSByW3doaWNoKGNvcnJlbGFjaW9uICE9IHIpWzFdXSwKICAgIGNvcnJlbGFfYiA9IHJbd2hpY2goY29ycmVsYWNpb24gIT0gcilbMl1dLAogICAgY29ycmVsYV9jID0gclt3aGljaChjb3JyZWxhY2lvbiAhPSByKVszXV0KICApCmBgYAoKT24gdGhlIGNvcnJlbGF0aW9ucyBpZGVudGlmaWVkIHRvIGJlIGdlbmVyYXRlZCwgdGhlIGRhdGEgbWF0cml4IG5lY2Vzc2FyeSBmb3IgdGhlIG11bHRpdmFyaWF0ZSBzaW11bGF0aW9uIGlzIGNyZWF0ZWQgYXMgYW4gb3V0bGllci4KCmBgYHtyfQpkZl93b3JrIDwtIGRmX3dvcmsgJT4lIAogIG11dGF0ZSgKICAgIG1hdHJpeCA9IG1hcChjb3JyZWxhY2lvbiwKICAgICAgICAgICAgICAgICB+IG1hdHJpeChkYXRhID0gcmVwKGMoMSwgcmVwKC54LCAyKSksIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikpLAogICAgbWF0cml4X2EgPSBtYXAoY29ycmVsYV9hLAogICAgICAgICAgICAgICAgICAgfiBtYXRyaXgoZGF0YSA9IHJlcChjKDEsIHJlcCgueCwgMikpLCAyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKSksCiAgICBtYXRyaXhfYiA9IG1hcChjb3JyZWxhX2IsCiAgICAgICAgICAgICAgICAgICB+IG1hdHJpeChkYXRhID0gcmVwKGMoMSwgcmVwKC54LCAyKSksIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpKSwKICAgIG1hdHJpeF9jID0gbWFwKGNvcnJlbGFfYywKICAgICAgICAgICAgICAgICAgIH4gbWF0cml4KGRhdGEgPSByZXAoYygxLCByZXAoLngsIDIpKSwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikpCiAgKSAlPiUgCiAgdW5ncm91cCgpCmBgYAoKQWdncmVnYXRlIG91dGxpZXJzIGFyZSBvZiAyIHR5cGVzOiB0aGV5IHZhcnkgb25seSBieSB0aGUgbWVhbiBhbmQgdGhleSB2YXJ5IGJ5IHRoZSBtZWFuIGFuZCBpdHMgbWF0cml4OgoKLSBvdXRsaWVyX20zOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiAzIAotIG91dGxpZXJfbTY6IFZhcmllcyBieSBhbiBtZWFuIG9mIDYKLSBvdXRsaWVyX20zdjE6IFZhcmllcyBieSBhbiBtZWFuIG9mIDMgYW5kIG1hdHJpeCBhCi0gb3V0bGllcl9tM3YyOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiAzIGFuZCBtYXRyaXggYgotIG91dGxpZXJfbTN2MzogVmFyaWVzIGJ5IGFuIG1lYW4gb2YgMyBhbmQgbWF0cml4IGMKLSBvdXRsaWVyX202djE6IFZhcmllcyBieSBhbiBtZWFuIG9mIDYgYW5kIG1hdHJpeCBhCi0gb3V0bGllcl9tNnYyOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiA2IGFuZCBtYXRyaXggYgotIG91dGxpZXJfbTZ2MzogVmFyaWVzIGJ5IGFuIG1lYW4gb2YgNiBhbmQgbWF0cml4IGMKCmBgYHtyfQpzZXQuc2VlZCgyMDE5KSAKCmRmX3dvcmsgPC0gZGZfd29yayAlPiUgCiAgbXV0YXRlKAogICAgb3V0bGllcl9tMyA9IG1hcDIocmF0aW9fb3V0bGllciwgbWF0cml4LCAKICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ybShuICAgICA9IC54LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ICAgID0gcmVwKDMsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpLAogICAgb3V0bGllcl9tNiA9IG1hcDIocmF0aW9fb3V0bGllciwgbWF0cml4LAogICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgICAgPSByZXAoNiwgMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX20zdjEgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9hLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgzLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX20zdjIgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9iLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgzLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX20zdjMgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9jLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgzLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX202djEgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9hLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX202djIgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9iLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX202djMgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9jLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSkKICApCmBgYAoKVGhlc2UgbmV3IHNpbXVsYXRlZCBvdXRsaWVyIGNvcnJlbGF0aW9ucyB3aWxsIGJlIGluc2VydGVkIGludG8gdGhlIGluaXRpYWxseSBjYWxjdWxhdGVkIHJhbmRvbSBwb3NpdGlvbnMgaW4gZWFjaCBkYXRhZnJhbWUuCgpgYGB7cn0KZGZfd29yayA8LSBkZl93b3JrICU+JSAKICBtdXRhdGUoCiAgICBkYXRhX291dF9tMyA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX20zLCBvdXRsaWVyX20zKSwKICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLAogICAgZGF0YV9vdXRfbTYgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tNiwgb3V0bGllcl9tNiksCiAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKSwKICAgIGRhdGFfb3V0X20zdjEgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tM3YxLCBvdXRsaWVyX20zdjEpLAogICAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoLi4zKSksCiAgICBkYXRhX291dF9tM3YyID0gcG1hcChsaXN0KGRhdGEsIHBvc2ljaV9yZXBfbTN2Miwgb3V0bGllcl9tM3YyKSwKICAgICAgICAgICAgICAgICAgICAgICAgIH4gLi4xICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLAogICAgZGF0YV9vdXRfbTN2MyA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX20zdjMsIG91dGxpZXJfbTN2MyksCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlKC0gLi4yKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKSwKICAgIGRhdGFfb3V0X202djEgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tNnYxLCBvdXRsaWVyX202djEpLAogICAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoLi4zKSksCiAgICBkYXRhX291dF9tNnYyID0gcG1hcChsaXN0KGRhdGEsIHBvc2ljaV9yZXBfbTZ2Miwgb3V0bGllcl9tNnYyKSwKICAgICAgICAgICAgICAgICAgICAgICAgIH4gLi4xICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLAogICAgZGF0YV9vdXRfbTZ2MyA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX202djMsIG91dGxpZXJfbTZ2MyksCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlKC0gLi4yKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKQogICkKYGBgCgpBZGRpdGlvbmFsbHksIG5ldyBkYXRhZnJhbWVzIHdpdGggdGhlIHNhbWUgY29ycmVsYXRpb24gY29uZGl0aW9ucywgc2FtcGxlIHNpemUgYW5kIG51bWJlciBvZiByZXBsaWNhdGlvbnMgd2l0aCBub24tbm9ybWFsIGRhdGEgZGlzdHJpYnV0aW9ucyBhcmUgZ2VuZXJhdGVkIHVzaW5nIHRoZSBhbGdvcml0aG0gb2YgVmFsZSBhbmQgTWF1cmVsbGkgKDE5ODMpLiAKCk5vbi1ub3JtYWxpdHkgY29uZGl0aW9ucyB3ZXJlIGdlbmVyYXRlZCBvbiB0aGUgYmFzaXMgb2YgdGhlIHdvcmsgb2YgW1NoZW5nICYgU2hlbmcgKDIwMTIpXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUMzMjc5NzI0Lyk6CgotIHNrZXduZXNzID0gMC4wMCwga3VydG9zaXMgPSDiiJIgMS4zODUgKHN5bW1ldHJpYyBwbGF0eWt1cnRpYyBkaXN0cmlidXRpb24pOwotIHNrZXduZXNzID0gMC4wMCwga3VydG9zaXMgPSAyNSAoc3ltbWV0cmljIGxlcHRva3VydGljIGRpc3RyaWJ1dGlvbik7Ci0gc2tld25lc3MgPSAwLjk2LCBrdXJ0b3NpcyA9IDAuMTMgKG5vbi1zeW1tZXRyaWMgZGlzdHJpYnV0aW9uKTsKLSBza2V3bmVzcyA9IDAuNDgsIGt1cnRvc2lzID0g4oiSIDAuOTIgKG5vbi1zeW1tZXRyaWMgcGxhdHlrdXJ0aWMgZGlzdHJpYnV0aW9uKTsKLSBza2V3bmVzcyA9IDIuNTAsIGt1cnRvc2lzID0gMjUgKG5vbi1zeW1tZXRyaWMgbGVwdG9rdXJ0aWMgZGlzdHJpYnV0aW9uKS4KCmBgYHtyfQpzZXQuc2VlZCgyMDIxKSAKbGlicmFyeShzZW1Ub29scykKCmRmX3dvcmsgPC0gZGZfd29yayAlPiUgCiAgbXV0YXRlKAogICAgZGF0YV9ub25vcm0xID0gbWFwMihuLCBtYXRyaXgsCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ubm9ybShuID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSA9IHJlcCgwLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzcyA9IGMoMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrdXJ0b3NpcyA9IGMoLTEuMzg1KSkgJT4lICMgc3ltbWV0cmljIHBsYXR5a3VydGljIGRpc3RyaWJ1dGlvbgogICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZSgpKSwKICAgIGRhdGFfbm9ub3JtMiA9IG1hcDIobiwgbWF0cml4LAogICAgICAgICAgICAgICAgICAgICAgICB+IG12cm5vbm5vcm0obiA9IC54LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgPSByZXAoMCwgMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaWdtYSA9IC55LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3MgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga3VydG9zaXMgPSAyNSkgJT4lICMgc3ltbWV0cmljIGxlcHRva3VydGljIGRpc3RyaWJ1dGlvbiAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBkYXRhX25vbm9ybTMgPSBtYXAyKG4sIG1hdHJpeCwKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub25ub3JtKG4gPSAueCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ID0gcmVwKDAsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNrZXduZXNzID0gMC45NiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gMC4xMykgJT4lICMgbm9uLXN5bW1ldHJpYyBkaXN0cmlidXRpb24KICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBkYXRhX25vbm9ybTQgPSBtYXAyKG4sIG1hdHJpeCwKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub25ub3JtKG4gPSAueCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ID0gcmVwKDAsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNrZXduZXNzID0gMC40OCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gLTAuOTIpICU+JSAjIG5vbi1zeW1tZXRyaWMgcGxhdHlrdXJ0aWMgZGlzdHJpYnV0aW9uCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpLAogICAgZGF0YV9ub25vcm01ID0gbWFwMihuLCBtYXRyaXgsCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ubm9ybShuID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSA9IHJlcCgwLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzcyA9IDIuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gMjUpICU+JSAjIG5vbi1zeW1tZXRyaWMgbGVwdG9rdXJ0aWMgZGlzdHJpYnV0aW9uCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpCiAgKQpgYGAKCkZpbmFsbHksIHRoZSB2YXJpYWJsZXMgdGhhdCB3aWxsIG5vIGxvbmdlciBiZSB1c2VkIGFyZSBlbGltaW5hdGVkLgoKYGBge3J9CmRmX3dvcmsgPC0gZGZfd29yayAlPiUgCiAgc2VsZWN0KC1jKHJhdGlvX291dGxpZXI6b3V0bGllcl9tNnYzKSkKCmRmX3dvcmsKYGBgCgoKIyBDYWxjdWxhdGlvbiBvZiBjb3JyZWxhdGlvbnMKCiMjIEZvcm1hdCB0aWR5IGRhdGEKYGBge3J9CmRmX3dvcmtfdGlkeSA8LSBkZl93b3JrICU+JSAKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gZGF0YTpkYXRhX25vbm9ybTUsCiAgICBuYW1lc190byA9ICJUaXBvX1NpbSIsCiAgICB2YWx1ZXNfdG8gPSAiRGF0YSIKICApCmBgYAoKIyMgU2V0dGluZ3MgbXVsdGljb3JlCmBgYHtyfQpsaWJyYXJ5KG11bHRpZHBseXIpCgppZiAoU3lzLmdldGVudigiUlNUVURJTyIpID09ICIxIiAmJiAhbnpjaGFyKFN5cy5nZXRlbnYoIlJTVFVESU9fVEVSTSIpKSAmJiAKICAgIChTeXMuaW5mbygpWyJzeXNuYW1lIl0gPT0gIkRhcndpbiIgfHwgU3lzLmluZm8oKVsic3lzbmFtZSJdID09ICJMaW51eCIpICYmIAogICAgZ2V0UnZlcnNpb24oKSA+PSAiNC4wLjAiKSB7CiAgcGFyYWxsZWw6OjpzZXREZWZhdWx0Q2x1c3Rlck9wdGlvbnMoc2V0dXBfc3RyYXRlZ3kgPSAic2VxdWVudGlhbCIpCn0KCmNsdXN0ZXIgPC0gbmV3X2NsdXN0ZXIocGFyYWxsZWw6OmRldGVjdENvcmVzKCkpCmBgYAoKIyMgQ29ycmVsYXRpb25zCgpgYGB7cn0KZGZfd29ya190aWR5IDwtIGRmX3dvcmtfdGlkeSAlPiUgCiAgcGFydGl0aW9uKGNsdXN0ZXIpICU+JSAKICBtdXRhdGUoCiAgICBjb3J0X3BlYXJzID0gcHVycnI6Om1hcChEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBjb3IudGVzdCgueCRWMSwgLngkVjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIikpLAogICAgY29ydF9zcGVhciA9IHB1cnJyOjptYXAoRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gY29yLnRlc3QoLngkVjEsIC54JFYyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3BlYXJtYW4iKSksCiAgICBjb3J0X3dpbnNvID0gcHVycnI6Om1hcChEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBXUlMyOjp3aW5jb3IoLngkVjEsIC54JFYyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHIgPSAwLjIpKQogICkgJT4lIAogIGNvbGxlY3QoKQpgYGAKCiMjIE9idGFpbiB0aGUgY29lZmZpY2llbnRzCgpgYGB7cn0KZGZfd29ya190aWR5IDwtIGRmX3dvcmtfdGlkeSAlPiUgCiAgbXV0YXRlKAogICAgY29lZl9wZWFycyA9IG1hcF9kYmwoY29ydF9wZWFycywKICAgICAgICAgICAgICAgICAgICAgICAgIH4gLngkZXN0aW1hdGUpLAogICAgY29lZl9zcGVhciA9IG1hcF9kYmwoY29ydF9zcGVhciwKICAgICAgICAgICAgICAgICAgICAgICAgIH4gLngkZXN0aW1hdGUpLAogICAgY29lZl93aW5zbyA9IG1hcF9kYmwoY29ydF93aW5zbywKICAgICAgICAgICAgICAgICAgICAgICAgIH4gLngkY29yKSwKICAgIHB2YWx1ZV9wZWFycyA9IG1hcF9kYmwoY29ydF9wZWFycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAueCRwLnZhbHVlKSwKICAgIHB2YWx1ZV9zcGVhciA9IG1hcF9kYmwoY29ydF9zcGVhciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAueCRwLnZhbHVlKSwKICAgIHB2YWx1ZV93aW5zbyA9IG1hcF9kYmwoY29ydF93aW5zbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAueCRwLnZhbHVlKQogICkKCmRmX3dvcmtfdGlkeV9zaW1wIDwtIGRmX3dvcmtfdGlkeSAlPiUgCiAgc2VsZWN0KC1jKERhdGE6Y29ydF93aW5zbykpCgpkZl93b3JrX3RpZHlfc2ltcApgYGAKCiMjIEdlbmVyYXRlIHBsb3QgYWJvdXQgcC12YWx1ZQoKIyMgUGxvdCB3aXRoIGNvbXBsZXRlIGNvbmRpdGlvbnMKCiMjIyBEYXRhIGZvcm1hdApgYGB7cn0KZGZfd29ya190aWR5X3B2YWx1ZSA8LSBkZl93b3JrX3RpZHlfc2ltcCAlPiUgCiAgbXV0YXRlKAogICAgYWNyb3NzKGMocHZhbHVlX3BlYXJzOnB2YWx1ZV93aW5zbyksCiAgICAgICAgICAgfiBjYXNlX3doZW4oCiAgICAgICAgICAgICAueCA8IC4wNSB+IDEsCiAgICAgICAgICAgICBUUlVFIH4gMAogICAgICAgICAgICkpLAogICAgY29ycmVsYWNpb24gPSBmYWN0b3IoY29ycmVsYWNpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMC4xMiIsICIwLjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAuMzEiLCAiMC41MCIpKSAKICApICU+JSAKICBncm91cF9ieShjb3JyZWxhY2lvbiwgbiwgVGlwb19TaW0pICU+JSAKICBzdW1tYXJpc2UoCiAgICBhY3Jvc3MoCiAgICAgIGMocHZhbHVlX3BlYXJzOnB2YWx1ZV93aW5zbyksCiAgICAgIH4gbWVhbiguKQogICAgKQogICkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IHB2YWx1ZV9wZWFyczpwdmFsdWVfd2luc28sCiAgICBuYW1lc190byA9ICJFc3RpbWF0b3IiLAogICAgdmFsdWVzX3RvID0gIlBvd2VyIgogICkgJT4lIAogIG11dGF0ZSgKICAgIEVzdGltYXRvciA9IGZjdF9yZWNvZGUoRXN0aW1hdG9yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiUGVhcnNvbiIgPSAicHZhbHVlX3BlYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNwZWFybWFuIiA9ICJwdmFsdWVfc3BlYXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiV2luc29yaXplZCIgPSAicHZhbHVlX3dpbnNvIikKICApCgoKZGZfd29ya190aWR5X3B2YWx1ZV9BIDwtIGRmX3dvcmtfdGlkeV9wdmFsdWUgJT4lIAogIG11dGF0ZSgKICAgIFRpcG9fU2ltID0gZmN0X3JlY29kZShUaXBvX1NpbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMiID0gImRhdGFfb3V0X20zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYiID0gImRhdGFfb3V0X202IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMgVjEiID0gImRhdGFfb3V0X20zdjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMiIgPSAiZGF0YV9vdXRfbTN2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYzIiA9ICJkYXRhX291dF9tM3YzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYgVjEiID0gImRhdGFfb3V0X202djEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMiIgPSAiZGF0YV9vdXRfbTZ2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYzIiA9ICJkYXRhX291dF9tNnYzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEEiID0gImRhdGFfbm9ub3JtMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBCIiA9ICJkYXRhX25vbm9ybTIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gQyIgPSAiZGF0YV9ub25vcm0zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEQiID0gImRhdGFfbm9ub3JtNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBFIiA9ICJkYXRhX25vbm9ybTUiKSwKICAgIFRpcG9fU2ltID0gZmN0X3JlbGV2ZWwoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4iLCAiT0wgTTMiLCAiT0wgTTYiLCAiT0wgTTMgVjEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYyIiwgIk9MIE0zIFYzIiwgIk9MIE02IFYxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYyIiwgIk9MIE02IFYzIikKICApICU+JSAKICBhcnJhbmdlKGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkKYGBgCgojIyMgUGxvdCBnZW5lcmF0aW9uCgpgYGB7cn0KcGxvdF9wb3dlcl9jb3JyZWxhdGlvbl9BIDwtIGdncGxvdChkZl93b3JrX3RpZHlfcHZhbHVlX0EsCiAgICAgICBhZXMoeCA9IFRpcG9fU2ltLAogICAgICAgICAgIHkgPSBQb3dlciwKICAgICAgICAgICBzaGFwZSA9IEVzdGltYXRvciwKICAgICAgICAgICBsaW5ldHlwZSA9IEVzdGltYXRvciwKICAgICAgICAgICBncm91cCA9IEVzdGltYXRvcikpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMzYTNhM2EiLCBzaXplID0gMikgKwogIGdlb21fcGF0aChjb2xvciA9ICIjM2EzYTNhIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEpLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMSwgMC4yKSkgKwogICAgbGFicyh0aXRsZSA9ICIiLAogICAgICAgICB4ID0gIlNpbXVsYXRpb24gY29uZGl0aW9ucyIsCiAgICAgICAgIHkgPSAiUG93ZXIgU3RhdGlzdGljcyIpICsKICBmYWNldF9ncmlkKGNvcnJlbGFjaW9uIH4gbikgKwogIHRoZW1lX2J3KCkgKyAKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgZmFjZT0iYm9sZCIpLCAKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDksCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA1NSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSA3LCByID0gMCwgYiA9IDAsIGwgPSAwKQogICAgKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMQogICAgKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siLAogICAgICBzaXplPTEwKSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuOCwgImxpbmVzIikKICApIApgYGAKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cmdnc2F2ZSgiaW1nL0V2YWx1YXRlX3Bvd2VyX2NvcnJlbGF0aW9uX0EucG5nIiwKICAgICAgIHBsb3QgPSBwbG90X3Bvd2VyX2NvcnJlbGF0aW9uX0EsCiAgICAgICBoZWlnaHQgPSA3LAogICAgICAgd2lkdGggPSAxNCwKICAgICAgIGRwaSA9IDQwMCkKYGBgCgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPScxMDAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9FdmFsdWF0ZV9wb3dlcl9jb3JyZWxhdGlvbl9BLnBuZyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGRwaSA9IDQwMCkKYGBgCgojIyBQbG90IHdpdGggc3VtbWFyaXNlZCBjb25kaXRpb25zCgojIyMgRGF0YSBmb3JtYXQKCmBgYHtyfQpkZl93b3JrX3RpZHlfcHZhbHVlX0IgPC0gZGZfd29ya190aWR5X3B2YWx1ZSAlPiUKICBtdXRhdGUoCiAgICBUaXBvX1NpbSA9IGZjdF9jb2xsYXBzZShUaXBvX1NpbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4iID0gIk1WTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIE9MIE0zIiA9ICJPTCBNMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIE9MIE02IiA9ICJPTCBNNiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIE9MIE0zViIgPSBjKCJPTCBNMyBWMSIsICJPTCBNMyBWMiIsICJPTCBNMyBWMyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNNlYiID0gYygiT0wgTTYgVjEiLCAiT0wgTTYgVjIiLCAiT0wgTTYgVjMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4iID0gYygiTm8tTVZOIEEiLCAiTm8tTVZOIEMiLCAiTm8tTVZOIEQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4ga3MrIiA9IGMoIk5vLU1WTiBCIiwgIk5vLU1WTiBFIikKICAgICkKICApIAoKZGZfd29ya190aWR5X3B2YWx1ZV9CIDwtIGRmX3dvcmtfdGlkeV9wdmFsdWVfQiAlPiUgCiAgZ3JvdXBfYnkoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltLCBFc3RpbWF0b3IpICU+JSAKICBzdW1tYXJpc2UoCiAgICBhY3Jvc3MoZXZlcnl0aGluZygpLCBtZWFuKQogICkgJT4lIAogIHVuZ3JvdXAoKQoKZGZfd29ya190aWR5X3B2YWx1ZV9CCmBgYAoKIyMjIFBsb3QgZ2VuZXJhdGlvbgoKYGBge3J9CnBsb3RfcG93ZXJfY29ycmVsYXRpb25fQiA8LSBnZ3Bsb3QoZGZfd29ya190aWR5X3B2YWx1ZV9CLAogICAgICAgYWVzKHggPSBUaXBvX1NpbSwKICAgICAgICAgICB5ID0gUG93ZXIsCiAgICAgICAgICAgc2hhcGUgPSBFc3RpbWF0b3IsCiAgICAgICAgICAgbGluZXR5cGUgPSBFc3RpbWF0b3IsCiAgICAgICAgICAgZ3JvdXAgPSBFc3RpbWF0b3IpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjM2EzYTNhIiwgc2l6ZSA9IDIpICsKICBnZW9tX3BhdGgoY29sb3IgPSAiIzNhM2EzYSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxKSwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDEsIDAuMikpICsKICAgIGxhYnModGl0bGUgPSAiIiwKICAgICAgICAgeCA9ICJTaW11bGF0aW9uIGNvbmRpdGlvbnMiLAogICAgICAgICB5ID0gIlBvd2VyIFN0YXRpc3RpY3MiKSArCiAgZmFjZXRfZ3JpZChjb3JyZWxhY2lvbiB+IG4pICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9ImJvbGQiKSwgCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSA5LAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gNywgciA9IDAsIGIgPSAwLCBsID0gMCkKICAgICksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEKICAgICksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiwKICAgICAgc2l6ZT0xMCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjgsICJsaW5lcyIpCiAgKSAKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpnZ3NhdmUoImltZy9FdmFsdWF0ZV9wb3dlcl9jb3JyZWxhdGlvbl9CLnBuZyIsCiAgICAgICBwbG90ID0gcGxvdF9wb3dlcl9jb3JyZWxhdGlvbl9CLAogICAgICAgaGVpZ2h0ID0gNywKICAgICAgIHdpZHRoID0gMTIsCiAgICAgICBkcGkgPSA0MDApCmBgYAoKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRXZhbHVhdGVfcG93ZXJfY29ycmVsYXRpb25fQi5wbmciLAogICAgICAgICAgICAgICAgICAgICAgICBkcGkgPSA0MDApCmBgYAoKCiMgRXZhbHVhdGUgc2ltdWxhdGlvbgoKIyMgQ2FsY3VsYXRlIFJNU0VBIGFuZCBCaWFzCgpgYGB7cn0KZGZfd29ya190aWR5X3NpbXAgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgbXV0YXRlKAogICAgZGlmX3BlYXJzID0gKGNvZWZfcGVhcnMgLSBjb3JyZWxhY2lvbikvY29ycmVsYWNpb24sCiAgICBkaWZfc3BlYXIgPSAoY29lZl9zcGVhciAtIGNvcnJlbGFjaW9uKS9jb3JyZWxhY2lvbiwKICAgIGRpZl93aW5zbyA9IChjb2VmX3dpbnNvIC0gY29ycmVsYWNpb24pL2NvcnJlbGFjaW9uCiAgKSAlPiUgCiAgdW5ncm91cCgpCgpkZl93b3JrX3RpZHlfc2ltcCA8LSBkZl93b3JrX3RpZHlfc2ltcCAlPiUgCiAgZ3JvdXBfYnkoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgcm1zZWFfcGVhcnMgPSBzcXJ0KHN1bShkaWZfcGVhcnNeMikvMTAwMCksCiAgICBzZXNnb19wZWFycyA9IChzdW0oZGlmX3BlYXJzKS8xMDAwKSwKICAgIHJtc2VhX3NwZWFyID0gc3FydChzdW0oZGlmX3NwZWFyXjIpLzEwMDApLAogICAgc2VzZ29fc3BlYXIgPSAoc3VtKGRpZl9zcGVhcikvMTAwMCksCiAgICBybXNlYV93aW5zbyA9IHNxcnQoc3VtKGRpZl93aW5zb14yKS8xMDAwKSwKICAgIHNlc2dvX3dpbnNvID0gKHN1bShkaWZfd2luc28pLzEwMDApCiAgKSAlPiUgCiAgdW5ncm91cCgpCgpkZl93b3JrX3RpZHlfc2ltcApgYGAKCiMjIFJlY29kZSBzaW11bGF0aW9uIHR5cGVzCgpgYGB7cn0KZGZfd29ya190aWR5X3NpbXAgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lIAogIG11dGF0ZSgKICAgIFRpcG9fU2ltID0gZmN0X3JlY29kZShUaXBvX1NpbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMiID0gImRhdGFfb3V0X20zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYiID0gImRhdGFfb3V0X202IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMgVjEiID0gImRhdGFfb3V0X20zdjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMiIgPSAiZGF0YV9vdXRfbTN2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYzIiA9ICJkYXRhX291dF9tM3YzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYgVjEiID0gImRhdGFfb3V0X202djEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMiIgPSAiZGF0YV9vdXRfbTZ2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYzIiA9ICJkYXRhX291dF9tNnYzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEEiID0gImRhdGFfbm9ub3JtMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBCIiA9ICJkYXRhX25vbm9ybTIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gQyIgPSAiZGF0YV9ub25vcm0zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEQiID0gImRhdGFfbm9ub3JtNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBFIiA9ICJkYXRhX25vbm9ybTUiKSwKICAgIFRpcG9fU2ltID0gZmN0X3JlbGV2ZWwoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4iLCAiT0wgTTMiLCAiT0wgTTYiLCAiT0wgTTMgVjEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYyIiwgIk9MIE0zIFYzIiwgIk9MIE02IFYxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYyIiwgIk9MIE02IFYzIikKICApICU+JSAKICBhcnJhbmdlKGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkKYGBgCgojIyBDb21wbGV0ZSB0YWJsZSBhYm91dCBSTVNFQSBhbmQgQmlhcwoKYGBge3J9CmRmX3dvcmtfdGlkeV9zaW1wX0EgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lIAogIHJlbG9jYXRlKGNvbnRhaW5zKCJzZXNnbyIpLCAuYWZ0ZXIgPSAicm1zZWFfd2luc28iKQoKZGZfd29ya190aWR5X3NpbXBfQQpgYGAKCiMjIFJlY2FsY3VsYXRpb24gb2YgUk1TRUEgYW5kIEJpYXMgZ3JvdXBpbmcgY29uZGl0aW9ucwoKYGBge3J9CmRmX3dvcmtfdGlkeV9zaW1wX0IgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lCiAgbXV0YXRlKAogICAgVGlwb19TaW0gPSBmY3RfY29sbGFwc2UoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJNVk4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNMyIgPSAiT0wgTTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNNiIgPSAiT0wgTTYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNM1YiID0gYygiT0wgTTMgVjEiLCAiT0wgTTMgVjIiLCAiT0wgTTMgVjMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTZWIiA9IGMoIk9MIE02IFYxIiwgIk9MIE02IFYyIiwgIk9MIE02IFYzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIiA9IGMoIk5vLU1WTiBBIiwgIk5vLU1WTiBDIiwgIk5vLU1WTiBEIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIGtzKyIgPSBjKCJOby1NVk4gQiIsICJOby1NVk4gRSIpCiAgICApCiAgKSAlPiUgCiAgcmVsb2NhdGUoY29udGFpbnMoInNlc2dvIiksIC5hZnRlciA9ICJybXNlYV93aW5zbyIpCgpkZl93b3JrX3RpZHlfc2ltcF9CIDwtIGRmX3dvcmtfdGlkeV9zaW1wX0IgJT4lIAogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIAogIHN1bW1hcmlzZSgKICAgIGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pCiAgKSAlPiUgCiAgdW5ncm91cCgpCgpkZl93b3JrX3RpZHlfc2ltcF9CCmBgYAoKIyMgRm9ybWF0IHRpZHkgZGF0YQoKYGBge3J9CmRmX3dvcmtfdGlkeV9zaW1wIDwtIGRmX3dvcmtfdGlkeV9zaW1wICU+JSAKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gcm1zZWFfcGVhcnM6c2VzZ29fd2luc28sCiAgICBuYW1lc190byA9ICJBanVzdGUiLAogICAgdmFsdWVzX3RvID0gIlZhbG9yIgogICkgJT4lIAogIG11dGF0ZSgKICAgIEFqdXN0ZSA9IGZjdF9yZWNvZGUoQWp1c3RlLAogICAgICAgICAgICAgICAgICAgICAgICAiUk1TRSBQZWFyc29uIiA9ICJybXNlYV9wZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJSTVNFIFNwZWFybWFuIiA9ICJybXNlYV9zcGVhciIsCiAgICAgICAgICAgICAgICAgICAgICAgICJSTVNFIFdpbnNvcml6ZWQiID0gInJtc2VhX3dpbnNvIiwKICAgICAgICAgICAgICAgICAgICAgICAgIlNlc2dvIFBlYXJzb24iID0gInNlc2dvX3BlYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgIlNlc2dvIFNwZWFybWFuIiA9ICJzZXNnb19zcGVhciIsCiAgICAgICAgICAgICAgICAgICAgICAgICJTZXNnbyBXaW5zb3JpemVkIiA9ICJzZXNnb193aW5zbyIpCiAgKQoKZGZfd29ya190aWR5X3NpbXAKYGBgCgojIyBQbG90cwoKCmBgYHtyfQpwbG90X2Fzc2Vzc19BIDwtIGRmX3dvcmtfdGlkeV9zaW1wICU+JQogIG11dGF0ZSgKICAgIGNvcnJlbGFjaW9uID0gZmFjdG9yKGNvcnJlbGFjaW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjMxIiwgIjAuNTAiKSkKICApICU+JSAKICBmaWx0ZXIoY29ycmVsYWNpb24gIT0gIjAuNTAiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVGlwb19TaW0sIHkgPSBWYWxvciwKICAgICAgICAgICAgICMgY29sb3VyID0gQWp1c3RlLAogICAgICAgICAgICAgc2hhcGUgPSBBanVzdGUsCiAgICAgICAgICAgICBsaW5ldHlwZSA9IEFqdXN0ZSwKICAgICAgICAgICAgIGdyb3VwID0gQWp1c3RlKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzNhM2EzYSIsIHNpemUgPSAyKSArCiAgZ2VvbV9wYXRoKGNvbG9yID0gIiMzYTNhM2EiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuNSwgNS41KSwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0wLjUsIDUuNSwgMSkpICsKICBsYWJzKHRpdGxlID0gIiIsCiAgICAgICB4ID0gIkNvbmRpY2lvbmVzIGRlIFNpbXVsYWNpw7NuIiwKICAgICAgIHkgPSAiIikgKwogICMgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpKSArCiAgZmFjZXRfZ3JpZChjb3JyZWxhY2lvbiB+IG4pICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgZmFjZT0iYm9sZCIpLCAKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDksCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSA3LCByID0gMCwgYiA9IDAsIGwgPSAwKQogICAgKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMQogICAgKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siLAogICAgICBzaXplPTEwKSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuOCwgImxpbmVzIikKICApIApgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRXZhbHVhdGVfY29ycmVsYXRpb25fUk1TRUFfQmlhc19BLnBuZyIpCmBgYAoKYGBge3J9CnBsb3RfYXNzZXNzX0IgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lCiAgbXV0YXRlKAogICAgY29ycmVsYWNpb24gPSBmYWN0b3IoY29ycmVsYWNpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMC4xMiIsICIwLjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAuMzEiLCAiMC41MCIpKQogICkgJT4lIAogIGZpbHRlcihjb3JyZWxhY2lvbiAhPSAiMC41MCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBUaXBvX1NpbSwgeSA9IFZhbG9yLAogICAgICAgICAgICAgIyBjb2xvdXIgPSBBanVzdGUsCiAgICAgICAgICAgICBzaGFwZSA9IEFqdXN0ZSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gQWp1c3RlLAogICAgICAgICAgICAgZ3JvdXAgPSBBanVzdGUpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjM2EzYTNhIiwgc2l6ZSA9IDIpICsKICBnZW9tX3BhdGgoY29sb3IgPSAiIzNhM2EzYSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC41LCA1LjUpLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoLTAuNSwgNS41LCAxKSkgKwogIGxhYnModGl0bGUgPSAiIiwKICAgICAgIHggPSAiQ29uZGljaW9uZXMgZGUgU2ltdWxhY2nDs24iLAogICAgICAgeSA9ICIiKSArCiAgIyBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMikpICsKICBmYWNldF9ncmlkKG4gfiBjb3JyZWxhY2lvbikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBmYWNlPSJib2xkIiksIAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gOSwKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBtYXJnaW4gPSBtYXJnaW4odCA9IDcsIHIgPSAwLCBiID0gMCwgbCA9IDApCiAgICApLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExCiAgICApLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIsCiAgICAgIHNpemU9MTApLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC44LCAibGluZXMiKQogICkgCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPScxMDAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9FdmFsdWF0ZV9jb3JyZWxhdGlvbl9STVNFQV9CaWFzX0IucG5nIikKYGBgCgpgYGB7cn0KcGxvdF9hc3Nlc3NfQyA8LSBkZl93b3JrX3RpZHlfc2ltcCAlPiUKICBtdXRhdGUoCiAgICBjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwLjEyIiwgIjAuMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC4zMSIsICIwLjUwIikpLAogICAgVGlwb19TaW0gPSBmY3RfY29sbGFwc2UoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJNVk4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNMyIgPSAiT0wgTTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNNiIgPSAiT0wgTTYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNM1YiID0gYygiT0wgTTMgVjEiLCAiT0wgTTMgVjIiLCAiT0wgTTMgVjMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTZWIiA9IGMoIk9MIE02IFYxIiwgIk9MIE02IFYyIiwgIk9MIE02IFYzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIiA9IGMoIk5vLU1WTiBBIiwgIk5vLU1WTiBDIiwgIk5vLU1WTiBEIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIGtzKyIgPSBjKCJOby1NVk4gQiIsICJOby1NVk4gRSIpKSwKICAgIEFqdXN0ZSA9IHN0cl9yZXBsYWNlKEFqdXN0ZSwgIlJNU0UiLCAiQVJNU0UiKSwKICAgIEFqdXN0ZSA9IHN0cl9yZXBsYWNlKEFqdXN0ZSwgIlNlc2dvIiwgIkJpYXMiKQogICkgJT4lICAKICBnZ3Bsb3QoYWVzKHggPSBUaXBvX1NpbSwgeSA9IFZhbG9yLAogICAgICAgICAgICAgIyBjb2xvdXIgPSBBanVzdGUsCiAgICAgICAgICAgICBzaGFwZSA9IEFqdXN0ZSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gQWp1c3RlLAogICAgICAgICAgICAgZ3JvdXAgPSBBanVzdGUpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjM2EzYTNhIiwgc2l6ZSA9IDIpICsKICBnZW9tX3BhdGgoY29sb3IgPSAiIzNhM2EzYSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC41LCA1LjUpLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoLTAuNSwgNS41LCAxKSkgKwogIGxhYnModGl0bGUgPSBOVUxMLAogICAgICAgeCA9ICJDb25kaXRpb25zIG9mIFNpbXVsYXRpb24iLAogICAgICAgeSA9IE5VTEwpICsKICAjIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKSkgKwogIGZhY2V0X2dyaWQoY29ycmVsYWNpb24gfiBuKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9ImJvbGQiKSwgCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSA5LAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gNywgciA9IDAsIGIgPSAwLCBsID0gMCkKICAgICksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEKICAgICksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiwKICAgICAgc2l6ZT0xMCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjgsICJsaW5lcyIpCiAgKSAKCgojIGdnc2F2ZShmaWxlbmFtZSA9ICJpbWcvRXZhbHVhdGVfY29ycmVsYXRpb25fUk1TRUFfQmlhc19DLnBuZyIsCiMgICAgICAgIHBsb3QgPSBwbG90X2Fzc2Vzc19DLCB3aWR0aCA9IDEwLjc1LCBoZWlnaHQgPSA3LCAKIyAgICAgICAgZHBpID0gMzAwKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRXZhbHVhdGVfY29ycmVsYXRpb25fUk1TRUFfQmlhc19DLnBuZyIpCmBgYAogCgojIEV2YWx1YXRlIG5vcm1hbGl0eQoKIyMgQ2FsY3VsYXRpb24gb2Yga3VydG9zaXMgYW5kIHNrZXduZXNzIGZvciBlYWNoIHZhcmlhYmxlCgpgYGB7cn0KbGlicmFyeShlMTA3MSkKCmRmX3dvcmtfdGlkeV9ldmFsdWF0ZSA8LSBkZl93b3JrX3RpZHkgJT4lIAogIG11dGF0ZSgKICAgIGt1cnRvc2lzX3YxID0gbWFwX2RibChEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgIH4ga3VydG9zaXMoLngkVjEsIHR5cGUgPSAyKSksCiAgICBrdXJ0b3Npc192MiA9IG1hcF9kYmwoRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICB+IGt1cnRvc2lzKC54JFYyLCB0eXBlID0gMikpLAogICAgc2tld25lc3NfdjEgPSBtYXBfZGJsKERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgfiBza2V3bmVzcygueCRWMSwgdHlwZSA9IDIpKSwKICAgIHNrZXduZXNzX3YyID0gbWFwX2RibChEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2tld25lc3MoLngkVjIsIHR5cGUgPSAyKSkKICApICU+JSAKICBzZWxlY3QoLWMoY29ydF9wZWFyczpjb2VmX3dpbnNvKSkKCmRmX3dvcmtfdGlkeV9ldmFsdWF0ZQpgYGAKCiMjIENhbGN1bGF0aW9uIGV2YWx1YXRpbmcgbXVsdGl2YXJpYXRlIG5vcm1hbGl0eQoKCiMjIyBFdmFsdWF0aW9uCgpgYGB7cn0KZGZfd29ya190aWR5X2V2YWx1YXRlIDwtIGRmX3dvcmtfdGlkeV9ldmFsdWF0ZSAlPiUgCiAgcGFydGl0aW9uKGNsdXN0ZXIpICU+JSAKICBtdXRhdGUoCiAgICBOb3JtYWxfbXVsdGlfciA9IHB1cnJyOjptYXBfY2hyKERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBNVk46Om12bigueCkkbXVsdGl2YXJpYXRlTm9ybWFsaXR5JFJlc3VsdFszXSksCiAgICBOb3JtYWxfbXVsdGlfciA9IGlmZWxzZShOb3JtYWxfbXVsdGlfciA9PSAiWUVTIiwgIlNpIiwgIk5vIikKICApICU+JSAKICBjb2xsZWN0KCkKYGBgCgojIyMgQ2F0ZWdvcml6ZSBieSBrdXJ0b3NpcyBhbmQgc2tld25lc3MKCmBgYHtyfQpkZl93b3JrX3RpZHlfZXZhbHVhdGUgPC0gZGZfd29ya190aWR5X2V2YWx1YXRlICU+JSAKICBtdXRhdGUoCiAgICBub3JtX3VuaSA9IGlmZWxzZShrdXJ0b3Npc192MSA+PSAtIDEuNSAmIGt1cnRvc2lzX3YxIDw9IDEuNSAmCiAgICAgICAgICAgICAgICAgICAgICAgIHNrZXduZXNzX3YxID49IC0gMS41ICYgc2tld25lc3NfdjEgPD0gMS41ICYKICAgICAgICAgICAgICAgICAgICAgICAga3VydG9zaXNfdjIgPj0gLSAxLjUgJiBrdXJ0b3Npc192MiA8PSAxLjUgJgogICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzc192MiA+PSAtIDEuNSAmIHNrZXduZXNzX3YyIDw9IDEuNSwgCiAgICAgICAgICAgICAgICAgICAgICAiU2kiLCAiTm8iKQogICkKYGBgCgojIyBGb3JtYXQgdGlkeSBkYXRhCgpgYGB7cn0KZGZfd29ya190aWR5X2V2YWx1YXRlIDwtIGRmX3dvcmtfdGlkeV9ldmFsdWF0ZSAlPiUKICBtdXRhdGUoCiAgICBUaXBvX1NpbSA9IGZjdF9yZWNvZGUoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiIgPSAiZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIiA9ICJkYXRhX291dF9tMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IiA9ICJkYXRhX291dF9tNiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYxIiA9ICJkYXRhX291dF9tM3YxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMgVjIiID0gImRhdGFfb3V0X20zdjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMyIgPSAiZGF0YV9vdXRfbTN2MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYxIiA9ICJkYXRhX291dF9tNnYxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYgVjIiID0gImRhdGFfb3V0X202djIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMyIgPSAiZGF0YV9vdXRfbTZ2MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBBIiA9ICJkYXRhX25vbm9ybTEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gQiIgPSAiZGF0YV9ub25vcm0yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEMiID0gImRhdGFfbm9ub3JtMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBEIiA9ICJkYXRhX25vbm9ybTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gRSIgPSAiZGF0YV9ub25vcm01IiksCiAgICBUaXBvX1NpbSA9IGZjdF9yZWxldmVsKFRpcG9fU2ltLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiwgIk9MIE0zIiwgIk9MIE02IiwgIk9MIE0zIFYxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMiIsICJPTCBNMyBWMyIsICJPTCBNNiBWMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMiIsICJPTCBNNiBWMyIpCiAgKSAlPiUgCiAgYXJyYW5nZShjb3JyZWxhY2lvbiwgbiwgVGlwb19TaW0pCgpkZl93b3JrX3RpZHlfZXZhbHVhdGUKYGBgCgojIyBEYXRhIGZvcm1hdCBmb3IgZXZhbHVhdGlvbgoKQ29tcGxldGU6CgpgYGB7cn0KZGZfd29ya190aWR5X0EgPC0gZGZfd29ya190aWR5X2V2YWx1YXRlICU+JSAKICBzZWxlY3QoY29ycmVsYWNpb246VGlwb19TaW0sIE5vcm1hbF9tdWx0aV9yOm5vcm1fdW5pKSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gTm9ybWFsX211bHRpX3I6bm9ybV91bmksCiAgICBuYW1lc190byA9ICJFdmFsdWFjacOzbiBOb3JtYWxpZGFkIiwKICAgIHZhbHVlc190byA9ICJEeCIKICApICU+JQogIG11dGF0ZSgKICAgIGBFdmFsdWFjacOzbiBOb3JtYWxpZGFkYCA9IGlmZWxzZShgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPT0gIk5vcm1hbF9tdWx0aV9yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3JtYWxpZGFkIG1hcmRpYSIsICJOb3JtYWxpZGFkIEFzIHkgS3MiKQogICkKYGBgCgpHcm91cGVkOgoKYGBge3J9CmRmX3dvcmtfdGlkeV9zaW1wX0IgPC0gZGZfd29ya190aWR5X2V2YWx1YXRlICU+JQogIG11dGF0ZSgKICAgIFRpcG9fU2ltID0gZmN0X2NvbGxhcHNlKFRpcG9fU2ltLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiIgPSAiTVZOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTMiID0gIk9MIE0zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTYiID0gIk9MIE02IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTNWIiA9IGMoIk9MIE0zIFYxIiwgIk9MIE0zIFYyIiwgIk9MIE0zIFYzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIE9MIE02ViIgPSBjKCJPTCBNNiBWMSIsICJPTCBNNiBWMiIsICJPTCBNNiBWMyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiIgPSBjKCJOby1NVk4gQSIsICJOby1NVk4gQyIsICJOby1NVk4gRCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBrcysiID0gYygiTm8tTVZOIEIiLCAiTm8tTVZOIEUiKQogICAgKQogICkgJT4lCiAgc2VsZWN0KGNvcnJlbGFjaW9uOlRpcG9fU2ltLCBOb3JtYWxfbXVsdGlfcjpub3JtX3VuaSkgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IE5vcm1hbF9tdWx0aV9yOm5vcm1fdW5pLAogICAgbmFtZXNfdG8gPSAiRXZhbHVhY2nDs24gTm9ybWFsaWRhZCIsCiAgICB2YWx1ZXNfdG8gPSAiRHgiCiAgKSAlPiUKICBtdXRhdGUoCiAgICBgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPSBpZmVsc2UoYEV2YWx1YWNpw7NuIE5vcm1hbGlkYWRgID09ICJOb3JtYWxfbXVsdGlfciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9ybWFsaWRhZCBtYXJkaWEiLCAiTm9ybWFsaWRhZCBBcyB5IEtzIikKICApCmBgYAoKCiMjIFBsb3RzCgojIyMgUGxvdCBNYXJkaWEgZnVsbAoKQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIGRhdGFmcmFtZXMgaWRlbnRpZmllZCBhcyBtdWx0aXZhcmlhdGUgbm9ybWFsIGluIGVhY2ggY29uZGl0aW9uLgoKYGBge3J9CmRmX3dvcmtfdGlkeV9BX21hcmRpYSA8LSBkZl93b3JrX3RpZHlfQSAlPiUgCiAgZmlsdGVyKGBFdmFsdWFjacOzbiBOb3JtYWxpZGFkYCA9PSAiTm9ybWFsaWRhZCBtYXJkaWEiKSAlPiUgCiAgY291bnQoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltLAogICAgICAgIER4LCBuYW1lID0gIkNhbnRpZGFkIikgJT4lIAogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIAogIG11dGF0ZShQb3JjZW50YWplID0gQ2FudGlkYWQvc3VtKENhbnRpZGFkKSkgJT4lIAogIHNlbGVjdCgtQ2FudGlkYWQpICU+JSAKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBEeCwKICAgIHZhbHVlc19mcm9tID0gUG9yY2VudGFqZSwKICAgIHZhbHVlc19maWxsID0gMAogICkgJT4lIAogIHVuZ3JvdXAoKQoKZGZfd29ya190aWR5X0FfbWFyZGlhCmBgYAoKUGxvdCBnZW5lcmF0aW9uOgoKYGBge3J9CnBsb3RfQV9tYXJkaWEgPC0gZGZfd29ya190aWR5X0FfbWFyZGlhICU+JSAKICBtdXRhdGUoY29ycmVsYWNpb24gPSBmYWN0b3IoY29ycmVsYWNpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAuMzEiLCAiMC41MCIpKSwKICAgICAgICAgY29ycmVsYWNpb24gPSBmY3RfcmV2KGNvcnJlbGFjaW9uKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFNpLCB5ID0gY29ycmVsYWNpb24sCiAgICAgICAgICAgICBhbHBoYSA9IGNvcnJlbGFjaW9uLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudChTaSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2N1cmFjeSA9IDEpKSkgKwogIGdlb21fY29sKCkgKwogIGZhY2V0X2dyaWQobiB+IFRpcG9fU2ltKSAgKwogIHNjYWxlX2FscGhhX2Rpc2NyZXRlKAogICAgbmFtZSA9ICJDb3JyZWxhY2nDs24iLAogICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpCiAgKSArIAogIHNjYWxlX3hfY29udGludW91cygKICAgIGxpbWl0cyA9IGMoMCwgMSksCiAgICBicmVha3MgPSBjKDAsIDAuMjUsIDAuNTAsIDAuNzUsIDEpLAogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLAogICAgZXhwYW5kID0gYygwLCAwLjEpLAogICAgZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKQogICkgKwogIGdlb21fbGFiZWwoCiAgICBzaXplID0gMy41LAogICAgbGFiZWwuc2l6ZSA9IDAuMjUsIAogICAgbGFiZWwuciA9IHVuaXQoMC4xNSwgImxpbmVzIiksCiAgICBsYWJlbC5wYWRkaW5nID0gdW5pdCgwLjE1LCAibGluZXMiKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGxhYnMoCiAgICB5ID0gIiIsCiAgICB4ID0gIiIKICApICsgCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBmYWNlPSJib2xkIiksIAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2UgPSAiYm9sZCIKICAgICksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiwKICAgICAgc2l6ZT0xMSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siLAogICAgICBzaXplPTExKSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNiwgImxpbmVzIikKICApIApgYGAKCiFbXShpbWcvUGxvdF9tYXJkaWFfY29tcGxldGVfc2FtcGxlLnBuZykKCgojIyMgUGxvdCBTa2V3bmVzcyBhbmQgS3VydG9zaXMgZnVsbAoKQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIGRhdGFmcmFtZXMgaWRlbnRpZmllZCBhcyB1bml2YXJpYXRlIG5vcm1hbGl0eSBpbiBlYWNoIGNvbmRpdGlvbi4KCmBgYHtyfQpkZl93b3JrX3RpZHlfQV9hc19rcyA8LSBkZl93b3JrX3RpZHlfQSAlPiUgCiAgZmlsdGVyKGBFdmFsdWFjacOzbiBOb3JtYWxpZGFkYCA9PSAiTm9ybWFsaWRhZCBBcyB5IEtzIikgJT4lIAogIGNvdW50KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSwKICAgICAgICBEeCwgbmFtZSA9ICJDYW50aWRhZCIpICU+JSAKICBncm91cF9ieShjb3JyZWxhY2lvbiwgbiwgVGlwb19TaW0pICU+JSAKICBtdXRhdGUoUG9yY2VudGFqZSA9IENhbnRpZGFkL3N1bShDYW50aWRhZCkpICU+JSAKICBzZWxlY3QoLUNhbnRpZGFkKSAlPiUgCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gRHgsCiAgICB2YWx1ZXNfZnJvbSA9IFBvcmNlbnRhamUsCiAgICB2YWx1ZXNfZmlsbCA9IDAKICApICU+JSAKICB1bmdyb3VwKCkKYGBgCgpQbG90IGdlbmVyYXRpb246CgpgYGB7cn0KcGxvdF9BX2FzX2tzIDwtIGRmX3dvcmtfdGlkeV9BX2FzX2tzICU+JSAKICBtdXRhdGUoY29ycmVsYWNpb24gPSBmYWN0b3IoY29ycmVsYWNpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAuMzEiLCAiMC41MCIpKSwKICAgICAgICAgY29ycmVsYWNpb24gPSBmY3RfcmV2KGNvcnJlbGFjaW9uKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFNpLCB5ID0gY29ycmVsYWNpb24sCiAgICAgICAgICAgICBhbHBoYSA9IGNvcnJlbGFjaW9uLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudChTaSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2N1cmFjeSA9IDEpKSkgKwogIGdlb21fY29sKCkgKwogIGZhY2V0X2dyaWQobiB+IFRpcG9fU2ltKSAgKwogIHNjYWxlX2FscGhhX2Rpc2NyZXRlKAogICAgbmFtZSA9ICJDb3JyZWxhY2nDs24iLAogICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpCiAgKSArIAogIHNjYWxlX3hfY29udGludW91cygKICAgIGxpbWl0cyA9IGMoMCwgMSksCiAgICBicmVha3MgPSBjKDAsIDAuMjUsIDAuNTAsIDAuNzUsIDEpLAogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLAogICAgZXhwYW5kID0gYygwLCAwLjEpLAogICAgZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKQogICkgKwogIGdlb21fbGFiZWwoCiAgICBzaXplID0gMy41LAogICAgbGFiZWwuc2l6ZSA9IDAuMjUsIAogICAgbGFiZWwuciA9IHVuaXQoMC4xNSwgImxpbmVzIiksCiAgICBsYWJlbC5wYWRkaW5nID0gdW5pdCgwLjE1LCAibGluZXMiKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGxhYnMoCiAgICB5ID0gIiIsCiAgICB4ID0gIiIKICApICsgCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBmYWNlPSJib2xkIiksIAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2UgPSAiYm9sZCIKICAgICksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiwKICAgICAgc2l6ZT0xMSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siLAogICAgICBzaXplPTExKSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNiwgImxpbmVzIikKICApIApgYGAKCgohW10oaW1nL1Bsb3Rfa3NfYXNfY29tcGxldGVfc2FtcGxlLnBuZykKCiMjIyBQbG90IE1hcmRpYSBncm91cGVkCgpDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgZGF0YWZyYW1lcyBpZGVudGlmaWVkIGFzIG11bHRpdmFyaWF0ZSBub3JtYWwgaW4gZWFjaCBjb25kaXRpb24uCgpgYGB7cn0KZGZfd29ya190aWR5X0JfbWFyZGlhIDwtIGRmX3dvcmtfdGlkeV9zaW1wX0IgJT4lIAogIGZpbHRlcihgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPT0gIk5vcm1hbGlkYWQgbWFyZGlhIikgJT4lIAogIGNvdW50KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSwKICAgICAgICBEeCwgbmFtZSA9ICJDYW50aWRhZCIpICU+JSAKICBncm91cF9ieShjb3JyZWxhY2lvbiwgbiwgVGlwb19TaW0pICU+JSAKICBtdXRhdGUoUG9yY2VudGFqZSA9IENhbnRpZGFkL3N1bShDYW50aWRhZCkpICU+JSAKICBzZWxlY3QoLUNhbnRpZGFkKSAlPiUgCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gRHgsCiAgICB2YWx1ZXNfZnJvbSA9IFBvcmNlbnRhamUsCiAgICB2YWx1ZXNfZmlsbCA9IDAKICApICU+JSAKICB1bmdyb3VwKCkKYGBgCgpQbG90IGdlbmVyYXRpb246CgpgYGB7cn0KcGxvdF9CX21hcmRpYSA8LSBkZl93b3JrX3RpZHlfQl9tYXJkaWEgJT4lIAogIG11dGF0ZShjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMC4xMiIsICIwLjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC4zMSIsICIwLjUwIikpLAogICAgICAgICBjb3JyZWxhY2lvbiA9IGZjdF9yZXYoY29ycmVsYWNpb24pKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gU2ksIHkgPSBjb3JyZWxhY2lvbiwKICAgICAgICAgICAgIGFscGhhID0gY29ycmVsYWNpb24sIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KFNpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY3VyYWN5ID0gMSkpKSArCiAgZ2VvbV9jb2woKSArCiAgZmFjZXRfZ3JpZChuIH4gVGlwb19TaW0pICArCiAgc2NhbGVfYWxwaGFfZGlzY3JldGUoCiAgICBuYW1lID0gIkNvcnJlbGFjacOzbiIsCiAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkKICApICsgCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygwLCAxKSwKICAgIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41MCwgMC43NSwgMSksCiAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksCiAgICBleHBhbmQgPSBjKDAsIDAuMSksCiAgICBndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpCiAgKSArCiAgZ2VvbV9sYWJlbCgKICAgIHNpemUgPSAzLjUsCiAgICBsYWJlbC5zaXplID0gMC4yNSwgCiAgICBsYWJlbC5yID0gdW5pdCgwLjE1LCAibGluZXMiKSwKICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMTUsICJsaW5lcyIpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgbGFicygKICAgIHkgPSAiIiwKICAgIHggPSAiIgogICkgKyAKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9ImJvbGQiKSwgCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgZmFjZSA9ICJib2xkIgogICAgKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siLAogICAgICBzaXplPTExKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIsCiAgICAgIHNpemU9MTEpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC42LCAibGluZXMiKQogICkgCmBgYAoKIVtdKGltZy9QbG90X21hcmRpYV9ncm91cGVkX2NvbXBsZXRlX3NpemUucG5nKQoKCiMjIyBQbG90IFNrZXduZXNzIGFuZCBLdXJ0b3NpcyBncm91cGVkCgoKQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIGRhdGFmcmFtZXMgaWRlbnRpZmllZCBhcyB1bml2YXJpYXRlIG5vcm1hbGl0eSBpbiBlYWNoIGNvbmRpdGlvbi4KCmBgYHtyfQpkZl93b3JrX3RpZHlfQl9hc19rcyA8LSBkZl93b3JrX3RpZHlfc2ltcF9CICU+JSAKICBmaWx0ZXIoYEV2YWx1YWNpw7NuIE5vcm1hbGlkYWRgID09ICJOb3JtYWxpZGFkIEFzIHkgS3MiKSAlPiUgCiAgY291bnQoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltLAogICAgICAgIER4LCBuYW1lID0gIkNhbnRpZGFkIikgJT4lIAogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIAogIG11dGF0ZShQb3JjZW50YWplID0gQ2FudGlkYWQvc3VtKENhbnRpZGFkKSkgJT4lIAogIHNlbGVjdCgtQ2FudGlkYWQpICU+JSAKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBEeCwKICAgIHZhbHVlc19mcm9tID0gUG9yY2VudGFqZSwKICAgIHZhbHVlc19maWxsID0gMAogICkgJT4lIAogIHVuZ3JvdXAoKQpgYGAKClBsb3QgR2VuZXJhdGlvbjoKCmBgYHtyfQpwbG90X0JfYXNfa3MgPC0gZGZfd29ya190aWR5X0JfYXNfa3MgJT4lIAogIG11dGF0ZShjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMC4xMiIsICIwLjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC4zMSIsICIwLjUwIikpLAogICAgICAgICBjb3JyZWxhY2lvbiA9IGZjdF9yZXYoY29ycmVsYWNpb24pKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gU2ksIHkgPSBjb3JyZWxhY2lvbiwKICAgICAgICAgICAgIGFscGhhID0gY29ycmVsYWNpb24sIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KFNpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY3VyYWN5ID0gMSkpKSArCiAgZ2VvbV9jb2woKSArCiAgZmFjZXRfZ3JpZChuIH4gVGlwb19TaW0pICArCiAgc2NhbGVfYWxwaGFfZGlzY3JldGUoCiAgICBuYW1lID0gIkNvcnJlbGFjacOzbiIsCiAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkKICApICsgCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygwLCAxKSwKICAgIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41MCwgMC43NSwgMSksCiAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksCiAgICBleHBhbmQgPSBjKDAsIDAuMSksCiAgICBndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpCiAgKSArCiAgZ2VvbV9sYWJlbCgKICAgIHNpemUgPSAzLjUsCiAgICBsYWJlbC5zaXplID0gMC4yNSwgCiAgICBsYWJlbC5yID0gdW5pdCgwLjE1LCAibGluZXMiKSwKICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMTUsICJsaW5lcyIpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgbGFicygKICAgIHkgPSAiIiwKICAgIHggPSAiIgogICkgKyAKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9ImJvbGQiKSwgCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgZmFjZSA9ICJib2xkIgogICAgKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siLAogICAgICBzaXplPTExKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIsCiAgICAgIHNpemU9MTEpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC42LCAibGluZXMiKQogICkgCmBgYAoKIVtdKGltZy9QbG90X2tzX2FzX2dyb3VwZWRfY29tcGxldGVfc2l6ZS5wbmcp